import { check, request, PERMISSIONS, RESULTS } from 'react-native-permissions';
import { Alert, PermissionsAndroid, Platform } from 'react-native';
import AudioRecorderPlayer, { AudioSet, AVEncoderAudioQualityIOSType, AVEncodingOption, AudioEncoderAndroidType, AudioSourceAndroidType, RecordBackType, PlayBackType } from 'react-native-audio-recorder-player';
import Toast from 'react-native-toast-message';
import RNFS from 'react-native-fs';

class AudioRecorderClass {
  private audioRecorderPlayer: AudioRecorderPlayer;
  private recordingStartTime: number | null;
  private audioFilePath: string | null;

  constructor() {
    this.audioRecorderPlayer = new AudioRecorderPlayer();
    this.recordingStartTime = null;
    this.audioFilePath = null;
  }

  /**
   * 是否有麦克风权限许可
   */
  public async hasRecordAudioPermission() {
    if (Platform.OS === 'android') {
      const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.RECORD_AUDIO);
      if (granted !== PermissionsAndroid.RESULTS.GRANTED) {
        Toast.show({ type: 'error', text1: '录音权限未被允许' });
        return false;
      }
    } else {
      const permission = await check(PERMISSIONS.IOS.MICROPHONE);
      if (permission !== RESULTS.GRANTED) {
        const result = await request(PERMISSIONS.IOS.MICROPHONE);
        if (result !== RESULTS.GRANTED) {
          Toast.show({ type: 'error', text1: '录音权限未被允许' });
          return false;
        }
      }
    }
    return true;
  }

  /**
   * 开始录音，返回 Promise，外部可以得到文件路径和录音时间
   * @param onProgress
   */
  public async startRecording(onProgress: (filePath: string | null, duration: number) => void): Promise<string | null> {
    const hasPermission = await this.hasRecordAudioPermission();
    if (!hasPermission) {
      Alert.alert('请打开麦克风权限');
      return Promise.reject(null);
    }
    const audioSet: AudioSet = {
      AudioEncoderAndroid: AudioEncoderAndroidType.AAC,
      AudioSourceAndroid: AudioSourceAndroidType.MIC,
      AVEncoderAudioQualityKeyIOS: AVEncoderAudioQualityIOSType.high,
      AVNumberOfChannelsKeyIOS: 2,
      AVFormatIDKeyIOS: AVEncodingOption.aac,
    };

    this.recordingStartTime = Date.now();
    const customFileName = `recording_${new Date().getTime()}.mp3`;
    const path = `${RNFS.DocumentDirectoryPath}/${customFileName}`;
    this.audioFilePath = await this.audioRecorderPlayer.startRecorder(path, audioSet);
    this.audioRecorderPlayer.addRecordBackListener((e: RecordBackType) => {
      const currentDuration = e.currentPosition;
      if (this.audioFilePath) {
        onProgress(this.audioFilePath, currentDuration);
      }
    });
    return this.audioFilePath;
  }

  /**
   * 停止录音，返回录音时长和文件路径
   */
  public async stopRecording(): Promise<{ filePath: string | null; duration: number }> {
    try {
      const result = await this.audioRecorderPlayer.stopRecorder();
      this.audioRecorderPlayer.removeRecordBackListener();

      if (this.recordingStartTime !== null) {
        const recordingEndTime = Date.now();
        const duration = recordingEndTime - this.recordingStartTime;
        console.log(`录音停止，持续时间: ${duration}ms, 路径: ${this.audioFilePath}`);
        return { filePath: this.audioFilePath, duration };
      } else {
        return { filePath: null, duration: 0 };
      }
    } catch (error) {
      Toast.show({ type: 'error', text1: '停止录音失败:' + error });
      return { filePath: null, duration: 0 };
    }
  }

  /**
   * 播放录音
   * @param audioFilePath
   * @param onPlayComplet
   * @param onPlayProgress
   */
  public async playRecording(audioFilePath: string, onPlayComplet: (hasComplete: boolean) => void, onPlayProgress: (progress: number) => void): Promise<void> {
    try {
      if (audioFilePath) {
        await this.audioRecorderPlayer.startPlayer(audioFilePath);
        this.audioRecorderPlayer.addPlayBackListener((e: PlayBackType) => {
          onPlayProgress(e.currentPosition);
          if (e.currentPosition === e.duration) {
            this.stopPlaying();
            onPlayComplet(true);
          }
        });
      } else {
        Toast.show({ type: 'error', text1: '没有可播放的声音文件' });
      }
    } catch (error) {
      Toast.show({ type: 'error', text1: '播放声音失败: ' + error });
    }
  }

  /**
   * 停止播放
   */
  public async stopPlaying() {
    await this.audioRecorderPlayer.stopPlayer();
    this.audioRecorderPlayer.removePlayBackListener();
    return true;
  }
}

export default AudioRecorderClass;
